package server.order;

import java.sql.ResultSet;
import java.sql.SQLException;

import server.Logger;
import server.conn.ConnectionThread;
import server.price.PriceController;

public class TrailingStopOrder extends Order {
	public static final String TRAIL_PERCENT = "trailPercent";
	
	private float trailPercent;
	
	/**
	 * Create a TrailingStopOrder from its ID
	 * @param id	Order ID
	 * @throws SQLException
	 */
	public TrailingStopOrder(int id) throws SQLException {
		super(id);
	}
	
	/**
	 * Create a TrailingStopOrder from a ResultSet
	 * @param rs	ResultSet containing TrailingStopOrder 
	 * @throws SQLException
	 */
	public TrailingStopOrder(ResultSet rs) throws SQLException {
		super(rs);
		rs.getFloat(TRAIL_PERCENT);
	}

	/**
	 * Create a TrailingStopOrder from all parameters
	 * @param cur1			Base currency
	 * @param cur2			Quote/Counter currency
	 * @param amount		Order amount
	 * @param bType			Buy or sell
	 * @param userId		UserID
	 * @param trailPercent	Percent (x.xx%) to trail current market price from
	 */
	public TrailingStopOrder(String cur1, String cur2, float amount, int bType, int userId, float trailPercent) {
		super(cur1, cur2, 0, amount, bType, userId, ORD_TRAILING_STOP, 0, false);
		this.trailPercent = trailPercent;
		
		if (getBType() == BUY)
			rate = PriceController.getInstance().getPrice(getCur1(), getCur2()).getBuy()*(1+(trailPercent/100));
		else
			rate = PriceController.getInstance().getPrice(getCur1(), getCur2()).getSell()*(1-(trailPercent/100));
		
		updateTrailRate();
	}
	
	/**
	 * @see Order#canClose()
	 */
	protected boolean canClose() {
		updateTrailRate();
		if (getBType() == BUY)
			return (super.canClose() && PriceController.getInstance().getPrice(getCur1(), getCur2()).getBuy() <= rate);
		else
			return (super.canClose() && PriceController.getInstance().getPrice(getCur1(), getCur2()).getSell() >= rate);
	}
	
	/**
	 * @see Order#canSatisfy(Order)
	 */
	public boolean canSatisfy(Order order) {
		if (typeCheck(order) && canClose()) {
			if (getBType() == BUY) {
				return (getRate() >= order.getRate());
			} else {
				return (getRate() <= order.getRate());
			}
		} else
			return false;
	}
	
	/**
	 * Update the trail rate based on current market prices
	 * @return new trail rate
	 */
	public float updateTrailRate() {
		float newTrailRate;
		
		if (getBType() == BUY) {
			newTrailRate = PriceController.getInstance().getPrice(getCur1(), getCur2()).getBuy()*(1+(trailPercent/100));
			if (newTrailRate < rate)
				rate = newTrailRate;
		} else {
			newTrailRate = PriceController.getInstance().getPrice(getCur1(), getCur2()).getSell()*(1-(trailPercent/100));
			if (newTrailRate > rate)
				rate = newTrailRate;
		}
		
		try {
			updateDB();
		} catch (SQLException e) { }
		
		return rate;
	}
	
	/**
	 * @see Order#addToDB()
	 */
	protected void addToDB() throws SQLException {
		String query = "";
		query += "INSERT INTO "+Order.TABLE+" (";
		query += Order.USER_ID+","+Order.CUR_1+","+Order.CUR_2+","+Order.RATE+","+Order.AMOUNT+","+Order.OPEN_TIME+","+Order.B_TYPE+","+Order.O_TYPE+","+Order.SPLIT+","+TRAIL_PERCENT+") ";
		query += "VALUES ("+userId+","+"\""+cur1+"\",\""+cur2+"\","+rate+","+amount+","+openTime+","+bType+","+oType+","+split+","+trailPercent+")";
		
		try {
			id = doUpdate(query);
		} catch (SQLException e) {
			Logger.getInstance().addSQLQueryError("Could not add order", query, 2);
			throw e;
		}
	}
	
	/**
	 * Update the trail rate in the database
	 * @throws SQLException
	 */
	private void updateDB() throws SQLException {
		String query = "UPDATE "+TABLE+" SET "+RATE+"="+rate+" WHERE "+ID+"="+id+" LIMIT 1";
		
		try {
			doUpdate(query);
		} catch (SQLException e) {
			Logger.getInstance().addSQLQueryError("Could not update order", query, 2);
			throw e;
		}
	}
	
	/**
	 * @return Order's trail percent
	 */
	public float getTrailPercent() { return trailPercent; }
	
	/**
	 * Return a string representation of the order
	 * @see Order#toString()
	 */
	public String toString() {
		String split = ConnectionThread.SPLIT;
		updateTrailRate();
		
		return super.toString()+split+trailPercent;
	}
}
